package 抽象语法树遍历器;

import 内存空间.*;
import 符号表和作用域.*;
import 抽象语法树类.*;
import 抽象语法树类.语句类.*;
import 抽象语法树类.字面量类.*;
import 抽象语法树类.表达式类.*;
import 抽象语法树类.表达式类.二元表达式类.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class 解释器 {

    private 内存空间 全局空间;
    private 内存空间 当前内存空间;
    private Stack<内存空间> 调用栈;

    private final 函数执行返回 返回 = new 函数执行返回();

    public StringBuilder 打印输出缓存;

    private void Log(String log) {
        System.out.println(log);
    }

    public void 解释(程序节点 入口点) {
        打印输出缓存 = new StringBuilder();
        全局空间 = new 内存空间("全局空间");
        当前内存空间 = 全局空间;
        调用栈 = new Stack<>();

        Log("创建全局空间");
        执行(入口点);
    }


    public Object 执行(抽象语法树 节点) {
        if (节点 instanceof 代码块) {
            执行代码块((代码块) 节点);
            return null;
        } else if (节点 instanceof 程序节点) {
            执行程序节点((程序节点) 节点);
            return null;
        } else if (节点 instanceof 语句) {
            return 执行语句((语句) 节点);
        } else if (节点 instanceof 表达式) {
            return 执行表达式((表达式) 节点);
        } else if (节点 instanceof 字面量) {
            return 执行字面量((字面量) 节点);
        } else if (节点 instanceof 函数定义) {
            return null;
        } else if (节点 instanceof 结构体定义) {
            return null;
        } else if (节点 instanceof 变量定义) {
            return null;
        } else if (节点 instanceof 符号引用 符号引用) {
            return 执行符号引用(符号引用);
        }

        throw new RuntimeException("[第" + 节点.start.getLine() + "行]不支持的节点类型：" + 节点.getClass().getName());
    }

    public void 执行代码块(代码块 节点) {
        for (抽象语法树 子节点 : 节点.语句列表) {
            执行(子节点);
        }
    }

    public void 执行程序节点(程序节点 节点) {
        for (var 子节点 : 节点.子节点) {
            执行(子节点);
        }
    }

    public Object 执行符号引用(符号引用 符号引用) {
        return 加载(符号引用);
    }

    // 语句类

    public Object 执行语句(语句 节点) {
        if (节点 instanceof If语句 if语句) {
            执行If语句(if语句);
            return null;
        } else if (节点 instanceof While语句 while语句) {
            执行While语句(while语句);
            return null;
        } else if (节点 instanceof 函数调用语句 函数调用语句) {
            return 执行函数调用语句(函数调用语句);
        } else if (节点 instanceof 返回语句 返回语句) {
            执行返回语句(返回语句);
            return null;
        } else if (节点 instanceof 打印语句 打印语句) {
            执行打印语句(打印语句);
            return null;
        } else if (节点 instanceof 赋值语句 赋值语句) {
            赋值语句(赋值语句);
            return null;
        }

        throw new RuntimeException("[第" + 节点.start.getLine() + "行]不支持的语句类型：" + 节点.getClass().getName());
    }

    public void 执行If语句(If语句 节点) {
        if ((boolean) 执行(节点.条件)) {
            执行(节点.真块);
        } else {
            if (节点.假块 != null) {
                执行(节点.假块);
            }
        }
    }

    public void 执行While语句(While语句 节点) {
        while ((boolean) 执行(节点.条件)) {
            执行(节点.代码块);
        }
    }

    public Object 执行函数调用语句(函数调用语句 节点) {
        var 符号 = 节点.作用域.解析(节点.函数名);
        if (符号 == null) {
            throw new RuntimeException("[第" + 节点.start.getLine() + "行]函数 \"" + 节点.函数名 + "\" 未定义");
        }

        if (!(符号 instanceof 函数符号 函数符号)) {
            throw new RuntimeException("[第" + 节点.start.getLine() + "行] \"" + 节点.函数名 + "\" 不是函数");
        }

        // 检查参数数量是否匹配
        var 需要参数个数 = 函数符号.取所有成员().size();
        var 实际参数个数 = 节点.参数.size();
        if (需要参数个数 != 实际参数个数) {
            throw new RuntimeException("[第" + 节点.start.getLine() + "行]函数 \"" + 节点.函数名 + "\" 需要 " + 需要参数个数 + " 个参数，但是实际传入了 " + 实际参数个数 + " 个");
        }

        // 执行参数里面的表达式并存储到函数空间里
        var 空间 = new 函数空间(函数符号);
        var 参数列表 = new ArrayList<>(函数符号.取所有成员().keySet());
        var 下标 = 0;
        for (var 参数 : 节点.参数) {
            var 参数值 = 执行(参数);
            空间.存储(参数列表.get(下标), 参数值);
            下标++;
        }

        var 存储 = 当前内存空间;
        当前内存空间 = 空间;

        // 执行函数
        Object 返回值 = null;
        调用栈.push(空间);

        try {
            Log("执行函数 " + 节点.函数名);
            执行(函数符号.代码块);
        } catch (函数执行返回 函数返回) {
            Log("函数返回 " + 函数返回.返回值);
            返回值 = 函数返回.返回值;
        }

        调用栈.pop();
        当前内存空间 = 存储;
        return 返回值;
    }

    public void 执行返回语句(返回语句 节点) {
        返回.返回值 = 执行(节点.返回值);
        throw 返回;
    }

    public void 执行打印语句(打印语句 节点) {
        var 值 = 执行(节点.表达式);
        打印输出缓存.append(值);
        System.out.println("[第" + 节点.start.getLine() + "行]打印输出：" + 标蓝(值));
    }

    private String 标蓝(Object 值) {
        return "\033[34m" + 值 + "\033[0m";
    }

    public void 赋值语句(赋值语句 节点) {
        var 值 = 执行(节点.右值);

        if (节点.左值 instanceof 成员访问表达式 成员访问) {
            字段赋值(成员访问, 值); // 形如 a.b = 1
            return;
        }

        // 变量赋值
        var 空间 = 取内存空间(节点.左值.toString());
        if (空间 == null) {
            空间 = 当前内存空间; // 在当前的空间中创建
        }

        空间.存储(节点.左值.toString(), 值);
    }

    public 内存空间 取内存空间(String 符号名) {
        if (!调用栈.isEmpty() && 调用栈.peek().取值(符号名) != null) {
            return 调用栈.peek();
        }

        if (全局空间.取值(符号名) != null) {
            return 全局空间;
        }

        return null;
    }


    public void 字段赋值(成员访问表达式 成员访问, Object 值) {
        var 结构体 = (结构体实例) 加载(成员访问.对象);
        var 字段名 = 成员访问.成员.toString();
        if (结构体.定义.解析(字段名) == null) {
            throw new RuntimeException("[第" + 成员访问.start.getLine() + "行]结构体 \"" + 结构体.定义.取名称() + "\" 中不存在字段 \"" + 字段名 + "\"");
        }

        结构体.存储(字段名, 值);
    }

    public Object 加载(抽象语法树 对象) {
        if (对象 instanceof 成员访问表达式 成员访问) {  // 树 ^('.' a b)
            return 加载字段(成员访问);
        }

        // 仅仅只有 a
        var 空间 = 取内存空间(对象.toString());
        if (空间 != null) {
            return 空间.取值(对象.toString()); // todo: ???? 不理解这里为什么要 空间.取值(对象.toString())
        }

        throw new RuntimeException("[第" + 对象.start.getLine() + "行]变量 \"" + 对象 + "\" 未定义");
    }


    public Object 加载字段(成员访问表达式 成员访问) {
        var 字段名 = 成员访问.成员.toString();

        var 结构体 = (结构体实例) 加载(成员访问.对象);
        if (结构体.定义.解析(字段名) == null) {
            throw new RuntimeException("[第" + 成员访问.start.getLine() + "行]结构体 \"" + 结构体.定义.取名称() + "\" 中不存在字段 \"" + 字段名 + "\"");
        }

        return 结构体.取值(字段名);
    }


    public Object 执行表达式(表达式 表达式) {
        if (表达式 instanceof 二元表达式 二元表达式) {
            return 执行二元表达式(二元表达式);
        } else if (表达式 instanceof 实例化表达式 实例化表达式) {
            return 执行实例化表达式(实例化表达式);
        } else if (表达式 instanceof 成员访问表达式 成员访问表达式) {
            return 执行成员访问表达式(成员访问表达式);
        }

        throw new RuntimeException("[第" + 表达式.start.getLine() + "行]不支持的表达式类型：" + 表达式.getClass().getName());
    }

    public Object 执行实例化表达式(实例化表达式 表达式) {
        var 结构体符号 = (结构体符号) 表达式.作用域.解析(表达式.类型名);
        return new 结构体实例(结构体符号);
    }

    public Object 执行成员访问表达式(成员访问表达式 表达式) {
        return 加载(表达式);
    }

    public Object 执行二元表达式(二元表达式 表达式) {
        if (表达式 instanceof 加法表达式 加法表达式) {
            return 执行加法表达式(加法表达式);
        } else if (表达式 instanceof 小于表达式 小于表达式) {
            return 执行小于表达式(小于表达式);
        } else if (表达式 instanceof 判等表达式 判等表达式) {
            return 执行判等表达式(判等表达式);
        } else if (表达式 instanceof 减法表达式 减法表达式) {
            return 执行减法表达式(减法表达式);
        } else if (表达式 instanceof 乘法表达式 乘法表达式) {
            return 执行乘法表达式(乘法表达式);
        }

        throw new RuntimeException("[第" + 表达式.start.getLine() + "行]不支持的二元表达式类型：" + 表达式.getClass().getName());
    }

    public Object 执行乘法表达式(乘法表达式 表达式) {
        return 二元算术运算(表达式);
    }

    private Object 二元算术运算(二元表达式 表达式) {
        var 左值 = 执行(表达式.左值);
        var 右值 = 执行(表达式.右值);


        if (左值 instanceof Double || 右值 instanceof Double) {
            if (表达式 instanceof 乘法表达式) {
                return ((Number) 左值).doubleValue() * ((Number) 右值).doubleValue();
            } else if (表达式 instanceof 加法表达式) {
                return ((Number) 左值).doubleValue() + ((Number) 右值).doubleValue();
            } else if (表达式 instanceof 减法表达式) {
                return ((Number) 左值).doubleValue() - ((Number) 右值).doubleValue();
            }
        }

        if (左值 instanceof Float || 右值 instanceof Float) {
            if (表达式 instanceof 乘法表达式) {
                return ((Number) 左值).floatValue() * ((Number) 右值).floatValue();
            } else if (表达式 instanceof 加法表达式) {
                return ((Number) 左值).floatValue() + ((Number) 右值).floatValue();
            } else if (表达式 instanceof 减法表达式) {
                return ((Number) 左值).floatValue() - ((Number) 右值).floatValue();
            }
        }

        if (左值 instanceof Integer || 右值 instanceof Integer) {
            if (表达式 instanceof 乘法表达式) {
                return ((Number) 左值).intValue() * ((Number) 右值).intValue();
            } else if (表达式 instanceof 加法表达式) {
                return ((Number) 左值).intValue() + ((Number) 右值).intValue();
            } else if (表达式 instanceof 减法表达式) {
                return ((Number) 左值).intValue() - ((Number) 右值).intValue();
            }
        }

        throw new RuntimeException("[第" + 表达式.start.getLine() + "行]二元算术运算操作数类型错误");
    }


    public Object 执行减法表达式(减法表达式 表达式) {
        return 二元算术运算(表达式);
    }

    public Object 执行判等表达式(判等表达式 表达式) {
        var 左值 = 执行(表达式.左值);
        var 右值 = 执行(表达式.右值);
        return 左值.equals(右值);
    }

    public Object 执行加法表达式(加法表达式 表达式) {
        var 左值 = 执行(表达式.左值);
        var 右值 = 执行(表达式.右值);

        if (左值 instanceof String || 右值 instanceof String) {
            return 左值.toString() + 右值.toString();
        }

        return 二元算术运算(表达式);
    }


    public Object 执行小于表达式(小于表达式 表达式) {
        var 左值 = 执行(表达式.左值);
        var 右值 = 执行(表达式.右值);

        if (左值 instanceof Integer && 右值 instanceof Integer) {
            return (int) 左值 < (int) 右值;
        }

        if (左值 instanceof Float && 右值 instanceof Float) {
            return (float) 左值 < (float) 右值;
        }

        if (左值 instanceof Double && 右值 instanceof Double) {
            return (double) 左值 < (double) 右值;
        }

        throw new RuntimeException("[第" + 表达式.start.getLine() + "行]小于操作数类型错误");
    }


    // 字面量类

    public Object 执行字面量(字面量 字面量) {
        if (字面量 instanceof 字符型字面量 字符型字面量) {
            return 执行字符型字面量(字符型字面量);
        } else if (字面量 instanceof 整数型字面量 整数型字面量) {
            return 执行整数型字面量(整数型字面量);
        } else if (字面量 instanceof 文本型字面量 文本型字面量) {
            return 执行文本型字面量(文本型字面量);
        } else if (字面量 instanceof 浮点型字面量 浮点型字面量) {
            return 执行浮点型字面量(浮点型字面量);
        }

        throw new RuntimeException("[第" + 字面量.start.getLine() + "行]不支持的字面量类型：" + 字面量.getClass().getName());
    }

    private String 去括号(String 内容) {
        return 内容.substring(1, 内容.length() - 1);
    }

    public Object 执行字符型字面量(字符型字面量 字面量) {
        var 内容 = 去括号(字面量.值.getText());
        if (内容.length() != 1) {
            throw new RuntimeException("[第" + 字面量.start.getLine() + "行]字符型字面量只能包含一个字符");
        }

        return 内容.charAt(0);
    }

    public Object 执行整数型字面量(整数型字面量 字面量) {
        return Integer.parseInt(字面量.值.getText());
    }

    public Object 执行文本型字面量(文本型字面量 字面量) {
        return 去括号(字面量.值.getText());
    }

    public Object 执行浮点型字面量(浮点型字面量 字面量) {
        return Double.parseDouble(字面量.值.getText());
    }
}
